/// `POST /_matrix/identity/*/3pid/bind`
///
/// Publish an association between a session and a Matrix user ID.
/// `/v2/` ([spec])
///
/// [spec]: https://spec.matrix.org/latest/identity-service-api/#post_matrixidentityv23pidbind
use crate::{thirdparty::Medium, UnixMillis, OwnedClientSecret, OwnedSessionId, OwnedUserId, ServerSignatures};
use crate::{thirdparty::Medium, OwnedClientSecret, OwnedSessionId};

use crate::{thirdparty::Medium, ClientSecret, OwnedSessionId, OwnedUserId};
use serde::{Deserialize, Serialize};

// const METADATA: Metadata = metadata! {
//     method: POST,
//     rate_limited: false,
//     authentication: AccessToken,
//     history: {
//         1.0 => "/_matrix/identity/v2/3pid/bind",
//     }
// };

/// Request type for the `bind_3pid` endpoint.

#[derive(ToSchema, Deserialize, Debug)]
pub struct BindThreepidReqBody {
    /// The session ID generated by the `requestToken` call.
    pub sid: OwnedSessionId,

    /// The client secret passed to the `requestToken` call.
    pub client_secret: OwnedClientSecret,

    /// The Matrix user ID to associate with the 3PIDs.
    pub mxid: OwnedUserId,
}

/// Response type for the `bind_3pid` endpoint.
#[derive(ToSchema,Serialize, Debug)]
pub struct BindThreepidResBody {
    /// The 3PID address of the user being looked up.
    pub address: String,

    /// The medium type of the 3PID.
    pub medium: Medium,

    /// The Matrix user ID associated with the 3PID.
    pub mxid: OwnedUserId,

    /// A UNIX timestamp before which the association is not known to be valid.
    pub not_before: UnixMillis,

    /// A UNIX timestamp after which the association is not known to be valid.
    pub not_after: UnixMillis,

    /// The UNIX timestamp at which the association was verified.
    pub ts: UnixMillis,

    /// The signatures of the verifying identity servers which show that the
    /// association should be trusted, if you trust the verifying identity services.
    pub signatures: ServerSignatures,
}

impl BindThreepidResBody {
    /// Creates a `Response` with the given 3PID address, medium, Matrix user ID, timestamps and
    /// signatures.
    pub fn new(
        address: String,
        medium: Medium,
        mxid: OwnedUserId,
        not_before: UnixMillis,
        not_after: UnixMillis,
        ts: UnixMillis,
        signatures: ServerSignatures,
    ) -> Self {
        Self {
            address,
            medium,
            mxid,
            not_before,
            not_after,
            ts,
            signatures,
        }
    }
}

/// `GET /_matrix/identity/*/3pid/getValidated3pid`
///
/// Determine if a given 3PID has been validated by a user.
/// `/v2/` ([spec])
///
/// [spec]: https://spec.matrix.org/latest/identity-service-api/#get_matrixidentityv23pidgetvalidated3pid
// const METADATA: Metadata = metadata! {
//     method: GET,
//     rate_limited: false,
//     authentication: AccessToken,
//     history: {
//         1.0 => "/_matrix/identity/v2/3pid/getValidated3pid/",
//     }
// };

/// Request type for the `check_3pid_validity` endpoint.

// pub struct CheckThreepidValidityReqBody {
//     /// The Session ID generated by the `requestToken` call.
//     #[salvo(parameter(parameter_in = Query))]
//     pub sid: OwnedSessionId,

//     /// The client secret passed to the `requestToken` call.
//     #[salvo(parameter(parameter_in = Query))]
//     pub client_secret: OwnedClientSecret,
// }

/// Response type for the `check_3pid_validity` endpoint.
#[derive(ToSchema,Serialize, Debug)]
pub struct CheckThreepidValidityResBody {
    /// The medium type of the 3PID.
    pub medium: Medium,

    /// The address of the 3PID being looked up.
    pub address: String,

    /// Timestamp, in milliseconds, indicating the time that the 3PID was validated.
    pub validated_at: u64,
}
impl CheckThreepidValidityResBody {
    /// Creates a `Response` with the given medium, address and validation timestamp.
    pub fn new(medium: Medium, address: String, validated_at: u64) -> Self {
        Self {
            medium,
            address,
            validated_at,
        }
    }
}

/// `POST /_matrix/identity/*/3pid/unbind`
///
/// Remove an association between a session and a Matrix user ID.
/// `/v2/` ([spec])
///
/// [spec]: https://spec.matrix.org/latest/identity-service-api/#post_matrixidentityv23pidunbind

// const METADATA: Metadata = metadata! {
//     method: POST,
//     rate_limited: false,
//     authentication: AccessToken,
//     history: {
//         1.0 => "/_matrix/identity/v2/3pid/unbind",
//     }
// };

/// Request type for the `unbind_3pid` endpoint.

#[derive(ToSchema, Deserialize, Debug)]
pub struct UnbindThreepidReqBody {
    /// The proof that the client owns the 3PID.
    ///
    /// If this is not provided, the request must be signed by the homeserver which controls
    /// the `mxid`.
    #[serde(flatten, skip_serializing_if = "Option::is_none")]
    pub threepid_ownership_proof: Option<ThreepidOwnershipProof>,

    /// The Matrix user ID to remove from the 3PIDs.
    pub mxid: OwnedUserId,

    /// The 3PID to remove.
    ///
    /// Must match the 3PID used to generate the session if using `sid` and `client_secret` to
    /// authenticate this request.
    pub threepid: ThirdPartyId,
}

/// A 3PID to unbind.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ThirdPartyId {
    /// A medium matching the medium of identifier to unbind.
    pub medium: Medium,

    /// The 3PID address to remove.
    pub address: String,
}

impl ThirdPartyId {
    /// Creates a new `ThirdPartyId` with the given medium and address.
    pub fn new(medium: Medium, address: String) -> Self {
        Self { medium, address }
    }
}

/// A proof that the client owns the 3PID.
///
/// Must be constructed using the same session ID and client secret generated and passed by the
/// `requestToken` call for the given 3PID.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ThreepidOwnershipProof {
    /// The Session ID generated by the `requestToken` call.
    pub sid: OwnedSessionId,

    /// The client secret passed to the `requestToken` call.
    pub client_secret: Box<ClientSecret>,
}

impl ThreepidOwnershipProof {
    /// Creates a new `ThreepidOwnershipProof` with the given session ID and client secret.
    pub fn new(sid: OwnedSessionId, client_secret: Box<ClientSecret>) -> Self {
        Self { sid, client_secret }
    }
}
